from mongoengine import fields

from models.meta import BaseDocument, BaseEmbeddedDocument, IdField
from utilities.enums import (
    SECURITYEVENT_PLUGINS_TUPLE,
    AvailabilityPlugins,
    CRAWLER_SCOPE,
    DEFAULT_CLOUD_ABNORMAL_NODES,
)
from utilities.enums import PreLoginMethod


class BaseTaskTypeConfig(BaseEmbeddedDocument):
    meta = {'abstract': True}

    task_id = IdField()


class VulJobConfigMap(BaseTaskTypeConfig):
    crawler_depth = fields.IntField(default=3)
    crawler_max_page = fields.IntField(default=100)
    # scan_profile = fields.IntField(default=1, choices=[1, 2, 3, 4, 5, 6])
    scan_profiles = fields.ListField(default=[1])


class SecurityEventJobConfigMap(BaseTaskTypeConfig):
    crawler_depth = fields.IntField(default=3)
    crawler_max_page = fields.IntField(default=100)
    include_plugins = fields.ListField(
        choices=list(SECURITYEVENT_PLUGINS_TUPLE), default=list(SECURITYEVENT_PLUGINS_TUPLE))
    crawler_scope = fields.IntField(choices=list(CRAWLER_SCOPE), default=2)
    include_url = fields.ListField(max_length=64, default=['/'])
    evidence = fields.BooleanField(default=True)


class AvailabilityJobConfigMap(BaseTaskTypeConfig):
    include_plugins = fields.ListField(choices=list(AvailabilityPlugins), default=list(AvailabilityPlugins))
    use_cloud = fields.BooleanField(default=True)
    cloud_abnormal_node = fields.IntField(default=DEFAULT_CLOUD_ABNORMAL_NODES)


class RiskLinkJobConfigMap(BaseTaskTypeConfig):
    crawler_depth = fields.IntField(default=3)
    crawler_max_page = fields.IntField(default=100)


class ChangeCheckJobConfigMap(BaseTaskTypeConfig):
    crawler_depth = fields.IntField(default=3)
    crawler_max_page = fields.IntField(default=100)
    crawler_scope = fields.IntField(choices=list(CRAWLER_SCOPE), default=2)
    include_url = fields.ListField(max_length=64, default=['/'])
    exclude_url = fields.ListField(max_length=64, default=[])
    text_change_ratio = fields.FloatField()
    structure_change_ratio = fields.FloatField()
    resource_change_ratio = fields.FloatField()
    automatic_update_baseline_interval = fields.IntField()
    is_automatic_update_baseline = fields.BooleanField(default=False)
    is_update_baseline = fields.BooleanField(default=False)
    is_delete_baseline = fields.BooleanField(default=False)
    is_check_text = fields.BooleanField(default=False)
    is_check_structure = fields.BooleanField(default=False)
    is_check_resource = fields.BooleanField(default=False)


class TargetInfoJobConfigMap(BaseTaskTypeConfig):
    enable = fields.BooleanField(default=True)


class BaseJobConfigMap(BaseEmbeddedDocument):
    meta = {'abstract': True}

    vul = fields.EmbeddedDocumentField(
        default=VulJobConfigMap, document_type=VulJobConfigMap
    )
    securityEvent = fields.EmbeddedDocumentField(
        default=SecurityEventJobConfigMap, document_type=SecurityEventJobConfigMap
    )
    availability = fields.EmbeddedDocumentField(
        default=AvailabilityJobConfigMap, document_type=AvailabilityJobConfigMap
    )
    risk_link = fields.EmbeddedDocumentField(
        default=RiskLinkJobConfigMap, document_type=RiskLinkJobConfigMap
    )
    target_info = fields.EmbeddedDocumentField(
        default=TargetInfoJobConfigMap, document_type=TargetInfoJobConfigMap
    )
    change_check = fields.EmbeddedDocumentField(
        default=ChangeCheckJobConfigMap, document_type=ChangeCheckJobConfigMap
    )


class BaseAdvanceConfig(BaseEmbeddedDocument):
    """
    Document: https://confluence.intra.knownsec.com/pages/viewpage.action?pageId=75596313
    """

    meta = {'abstract': True}

    requests_per_sec = fields.IntField(default=0)
    concurrency = fields.IntField(default=0)
    is_filter_by_query_key = fields.BooleanField(default=True)
    request_timeout = fields.IntField(default=0)
    crawler_included_urls = fields.ListField(default=[])
    crawler_excluded_urls = fields.ListField(default=[])
    site_login = fields.BooleanField(default=False)
    login_method = fields.StringField(
        default=PreLoginMethod.form.value, choices=[item.value for item in PreLoginMethod])
    login_json_action_url = fields.StringField()
    login_json_postdata = fields.StringField()
    login_form_action_url = fields.StringField()
    login_form_postdata = fields.StringField()
    request_cookie = fields.StringField()
    request_http_headers = fields.StringField()

    is_http_auth_enabled = fields.BooleanField(default=False)
    http_auth_username = fields.StringField()
    http_auth_password = fields.StringField()

    is_proxy_enabled = fields.BooleanField(default=False)
    is_proxy_need_auth = fields.BooleanField(default=True)
    proxy_scheme = fields.StringField(default='http', choices=['http'])
    proxy_host = fields.StringField()
    proxy_port = fields.IntField()
    proxy_username = fields.StringField()
    proxy_password = fields.StringField()
    request_user_agent = fields.StringField()

    is_deep_malscan = fields.BooleanField(default=False)


class TargetGroupAdvanceConfig(BaseAdvanceConfig):
    pass


class TargetAdvanceConfig(BaseAdvanceConfig):
    is_solo = fields.BooleanField(default=False)


class TargetGroupJobConfigMap(BaseJobConfigMap):
    pass


class TargetJobConfigMap(BaseJobConfigMap):
    is_solo = fields.BooleanField(default=False)


class PeriodConfig(BaseEmbeddedDocument):
    # seconds = fields.LongField(default=86400, min_value=1800)
    seconds = fields.LongField(default=1800, min_value=60)
    is_disabled = fields.BooleanField(default=False)


class VulPeriodConfig(BaseEmbeddedDocument):
    # seconds = fields.LongField(default=86400, min_value=3600)
    seconds = fields.LongField(default=3600, min_value=60)
    is_disabled = fields.BooleanField(default=False)


class AvailabilityPeriodConfig(BaseEmbeddedDocument):
    # seconds = fields.LongField(default=86400, min_value=900)
    seconds = fields.LongField(default=1800, min_value=60)
    is_disabled = fields.BooleanField(default=False)


class TargetInfoPeriodConfig(BaseEmbeddedDocument):
    seconds = fields.LongField(default=86400, min_value=60)
    is_disabled = fields.BooleanField(default=False)


class WarnInfo(BaseEmbeddedDocument):
    availability = fields.BooleanField(default=True)
    securityEvent = fields.BooleanField(default=True)
    vul = fields.BooleanField(default=True)
    risk_link = fields.BooleanField(default=True)
    change_check = fields.BooleanField(default=True)


class BaseTaskConfig(BaseEmbeddedDocument):
    meta = {'abstract': True}

    promptly = fields.BooleanField(default=True)
    is_periodic = fields.BooleanField(default=False)
    start_at = fields.StringField(default='')
    end_at = fields.StringField(default='')
    scan_period_start_time = fields.StringField(default='')
    scan_period_end_time = fields.StringField(default='')
    use_increment = fields.BooleanField(default=False)
    vul = fields.EmbeddedDocumentField(default=VulPeriodConfig, document_type=VulPeriodConfig)
    securityEvent = fields.EmbeddedDocumentField(
        default=PeriodConfig, document_type=PeriodConfig
    )
    availability = fields.EmbeddedDocumentField(
        default=PeriodConfig, document_type=PeriodConfig
    )
    risk_link = fields.EmbeddedDocumentField(
        default=PeriodConfig, document_type=PeriodConfig
    )
    change_check = fields.EmbeddedDocumentField(
        default=PeriodConfig, document_type=PeriodConfig
    )
    target_info = fields.EmbeddedDocumentField(
        default=TargetInfoPeriodConfig, document_type=TargetInfoPeriodConfig
    )
    warn_info = fields.EmbeddedDocumentField(default=WarnInfo, document_type=WarnInfo)
    receiver_list = fields.ListField(max_length=128)


class TargetGroupTaskConfig(BaseTaskConfig):
    pass


class TargetTaskConfig(BaseTaskConfig):
    is_solo = fields.BooleanField(default=False)


class Targets(BaseDocument):
    target_id = IdField(required=True, unique=True)
    user_id = IdField(required=True)
    target_url = fields.StringField(required=True, max_length=1024)
    target_name = fields.StringField(max_length=50, default='')
    target_title = fields.StringField(default='')
    target_group_id = IdField(required=True)

    task_config = fields.EmbeddedDocumentField(default=TargetTaskConfig, document_type=TargetTaskConfig)
    job_config_map = fields.EmbeddedDocumentField(
        default=TargetJobConfigMap, document_type=TargetJobConfigMap
    )
    advance_config = fields.EmbeddedDocumentField(
        default=TargetAdvanceConfig, document_type=TargetAdvanceConfig
    )

    meta = {
        'indexes': ['user_id', 'target_id'],
        'ordering': ['-created_at'],
        'collection': "scan_targets",
        'primary_key': 'target_id',
    }


class TargetGroups(BaseDocument):
    target_group_id = IdField(required=True, unique=True)
    target_group_name = fields.StringField(max_length=32, required=True, unique=True)
    user_id = IdField(required=True)

    task_config = fields.EmbeddedDocumentField(
        default=TargetGroupTaskConfig, document_type=TargetGroupTaskConfig
    )
    job_config_map = fields.EmbeddedDocumentField(
        default=TargetGroupJobConfigMap, document_type=TargetGroupJobConfigMap
    )
    advance_config = fields.EmbeddedDocumentField(
        default=TargetGroupAdvanceConfig, document_type=TargetGroupAdvanceConfig
    )

    enable = fields.BooleanField(default=False)

    meta = {
        'indexes': ['user_id', 'target_group_id'],
        'ordering': ['-created_at'],
        'collection': "scan_target_groups",
        'primary_key': 'target_group_id',
    }


class PendingDeletionTargetGroups(BaseDocument):
    target_group_id = IdField(required=True)
    target_id = IdField(required=True)
    is_cleaned = fields.BooleanField(default=False)

    meta = {
        'indexes': ['target_group_id', 'target_id'],
        'ordering': ['-created_at'],
        'collection': 'scan_target_groups_deleted',
        'primary_key': 'target_id',
    }
